﻿#Requires -Version 2
$ErrorActionPreference = "Stop";
Set-PSDebug -Strict;
$Error.Clear();

$DEPLOYMENT_DIRECTORY=(Split-Path -Path $MyInvocation.MyCommand.Definition -Parent);

. ( Join-Path -Path $DEPLOYMENT_DIRECTORY -ChildPath "UtilityScripts\CommerceServer2007.ps1");
. ( Join-Path -Path $DEPLOYMENT_DIRECTORY -ChildPath "UtilityScripts\CommerceServer2007_Profiles.ps1");
. ( Join-Path -Path $DEPLOYMENT_DIRECTORY -ChildPath "UtilityScripts\CommerceServer2007_Catalog.ps1");
. ( Join-Path -Path $DEPLOYMENT_DIRECTORY -ChildPath "UtilityScripts\CommerceServer2007_MSCSAdmin.ps1");
. ( Join-Path -Path $DEPLOYMENT_DIRECTORY -ChildPath "UtilityScripts\IIS.ps1");
. ( Join-Path -Path $DEPLOYMENT_DIRECTORY -ChildPath "UtilityScripts\Windows.ps1");
. ( Join-Path -Path $DEPLOYMENT_DIRECTORY -ChildPath "UtilityScripts\File.ps1");
. ( Join-Path -Path $DEPLOYMENT_DIRECTORY -ChildPath "UtilityScripts\AZMan.ps1");
. ( Join-Path -Path $DEPLOYMENT_DIRECTORY -ChildPath "UtilityScripts\SQL.ps1");

<#
.Synopsis
	Using the Environment.xml file, create a Commerce Server site
.Description
	
.Example
	Deploy-CommerceServer -ConfigurationIdentity "Domain.Dev.Unpup" -PreCompile;
	Runs the Domain.Dev.Unpup configuration and all actions that normally happen under preCompile
.Example
	Deploy-CommerceServer -ConfigurationIdentities @("Domain.Dev.Unpup","Domain.Dev")
	Runs the Domain.Dev.Unpup and Domain.Dev configurations
.Parameter Precompile
	Runs precompile for the solution.
.Parameter Postcompile
	Runs postcompile for the solution.	
.Parameter ConfigurationIdentities
	An array of strings that coorespond to one or more of the identity attributes of the <Configurations><Configuration> node of the Environment.xml.
#>
function Deploy-CommerceServer
(
	[switch]$Precompile = $false,
	[switch]$Postcompile = $false,
	[string]$ConfigurationIdentity="Domain.Dev",
	$DeploymentIdentities=@()
)
{
	Clear-Host;

	$scriptStartDate = Get-Date;
	$transactionLogPath = ( Join-Path -Path $DEPLOYMENT_DIRECTORY -ChildPath "Deploy-CommerceServer.log" );
	$success = "FAILED";

	try
	{
		Start-Transcript -Force -Path $transactionLogPath -Debug -Confirm:$false;

		Write-Host "Script started @ $($scriptStartDate).";

		Clear-EventLog -LogName "Application";
		Clear-EventLog -LogName "System";
		Clear-EventLog -LogName "Windows PowerShell";

		Write-Host "Restarting IIS";
		#IISRESET
		
		$environmentXml = [xml]( Get-Content -Path ( Join-Path -Path $DEPLOYMENT_DIRECTORY -ChildPath "Environment.xml" ) );

		$configuration = $environmentXml.CommerceServer.Configurations.Configuration | where { $_.identity -ieq $ConfigurationIdentity };
		if( $configuration )
		{
			Write-Host "Using configuration $($configuration.identity)";

			Write-Host "Loading variables";
			
			$variables = $configuration.SelectNodes("Variables/Variable");

			foreach( $variable in $variables )
			{
				$variableValue =  $ExecutionContext.InvokeCommand.ExpandString( ( ( ( $variable.value -replace '&quot;', '`"') -replace '''', '`''') ) );
				
				Write-Host "$($variable.identity) = $($variableValue)" -ForegroundColor Green;
				Set-Variable -Name $variable.identity -Value $variableValue -Scope Global;
			}

			foreach( $node in $configuration.SelectNodes( ".//*" ) )
			{
				foreach( $attribute in $node.Attributes )
				{
					$attribute.Value = $ExecutionContext.InvokeCommand.ExpandString( ( ( ( $attribute.Value -replace '&quot;', '`"') -replace '''', '`''') ) )
				}
			}
		}
		else
		{
			Write-Error "No configuration with the identity $($ConfigurationIdentity) was found in the Environment.xml file.";
		}

		#Get-Variable | ft Name, Value -auto
		Write-Host "Writing complete variable list..." -ForegroundColor Green;
		Get-Variable | out-default;

		if( $Precompile )
		{
			Import-Module WebAdministration;
			
			Stop-Website -Name "Default Web Site";
			
			if($configuration.UserGroups -and $configuration.UserGroups.UserGroup){
			
				Write-Host "Adding users to groups..." -ForegroundColor Green;
				
				$userGroups = $configuration.UserGroups.SelectNodes("UserGroup");
				
				foreach( $userGroup in $userGroups )
				{
					if($userGroup.Users.User){
						$users = $userGroup.Users.SelectNodes("User");
						
						foreach( $user in $users )
						{						
							$actualUser = $configuration.UserAccounts.UserAccount | where { $_.identity -ieq $($user.userAccountIdentity) }
							
							Windows-AddUserToLocalGroup -LocalGroupName $userGroup.name -UserName "$($actualUser.domain)\$($actualUser.username)";
						}
					}
				}
			}	
			
			if($configuration.Events -and $configuration.Events.Definition){
			
				Write-Host "Registering new events for the event log..." -ForegroundColor Green;
				
				$events = $configuration.Events.SelectNodes("Definition");
				
				foreach( $event in $events )
				{
					Add-NewEventLogSource $event.EventSource;
				}
			}			
																
			if($configuration.IIS){
				# IIS Sites
				if( $configuration.IIS.Websites -and $configuration.IIS.Websites.Website ){
					$websites = $configuration.IIS.SelectNodes("Websites/Website");
					
					Write-Host "Creating sites..." -ForegroundColor Green;
					foreach( $website in $websites )
					{
						Write-Host "Working on $($website.identity) site..." -ForegroundColor Yellow;
						$siteInstance = Get-WebSite | where { $_.Name -eq $($website.identity) };

						if($siteInstance -ne $null){
							if($website.deleteIfExists -eq "true"){
								Write-Host "Site $($website.identity) exists, deleting...";

								Remove-Item "IIS:\Sites\$($website.identity)" -recurse;

								$siteInstance = $null;
							}
						}
						else{
							Write-Host "Site $($website.identity) does not exist.";
						}

						if($siteInstance -eq $null)
						{
							if($website.create -eq "true"){
								Write-Host "Site $($website.identity) does not exist, creating...";

								$siteInstance = New-Item "IIS:\Sites\$($website.identity)" -PhysicalPath "$($website.path)" -bindings @{protocol="$($website.protocol)";bindingInformation="*:$($website.port):"};
								
								Assign-AppPoolToSite $configuration $website.applicationPool "$($website.identity)";
							}
							else{
								Write-Host "Will not create $($website.identity).";
							}
						}
						
						if($siteInstance -and $website.VirtualDirectories -and $website.VirtualDirectories.VirtualDirectory){
							$vds = $website.SelectNodes("VirtualDirectories/VirtualDirectory");
							
							foreach($vd in $vds){
								$vdInstance = Get-ChildItem "IIS:\Sites\$($website.identity)" | where { $_.Name -eq $($vd.identity) };
								
								if($vdInstance -ne $null){
									if($vd.deleteIfExists -eq "true"){
										Write-Host "Virtual Directory $($vd.identity) exists, deleting...";

										Remove-Item "IIS:\Sites\$($website.identity)\$($vd.identity)" -recurse;

										$vdInstance = $null;
									}
									else{
										Write-Host "Virtual Directory $($vd.identity) exists.";
									}
								}
								
								if($vdInstance -eq $null)
								{
									if($vd.create -eq "true"){
										Write-Host "Creating Virtual Directory $($vd.identity)";
										
										if($vd.applicationPool -ne $null){
											$vdInstance = New-Item "IIS:\Sites\$($website.identity)\$($vd.identity)" -Type Application -PhysicalPath "$($vd.path)";
										
											Assign-AppPoolToSite $configuration $vd.applicationPool "$($website.identity)\$($vd.identity)" $true;
										}
										else{
											$vdInstance = New-Item "IIS:\Sites\$($website.identity)\$($vd.identity)" -Type VirtualDirectory -PhysicalPath "$($vd.path)";
										}
									}
								}						
							}
						}
						else{
							Write-Host "$($website.identity) does not exist so cannot create virtual directories." -ForegroundColor Yellow;
						}
					}
				
					Write-Host "Done." -ForegroundColor Yellow;
				}
				
				# IIS Certificates
				if( $configuration.IIS.Certificates -and $configuration.IIS.Certificates.Certificate ){
					$certificates = $configuration.IIS.SelectNodes("Certificates/Certificate");
					
					Write-Host "Importing certificates..." -ForegroundColor Green;
					foreach( $iisCertificate in $certificates )
					{
						$cert = ( Get-ChildItem -Path "cert:\localmachine\MY" | where { $_.FriendlyName -ieq $iisCertificate.identity -or $_.Subject -ieq "CN=$($iisCertificate.identity)" });

						if( $cert -ne $null )
						{
							Write-Host "Deleting pre-existing certificate: $($iisCertificate.identity)";
							
							$store = New-Object System.Security.Cryptography.X509Certificates.X509Store "My", "localmachine"
							$store.Open("ReadWrite")
							$store.Remove($cert)
							$store.Close()
						}

						if($iisCertificate.selfSigned -and $iisCertificate.selfSigned -eq "true"){
							Create-SelfSignedCert $iisCertificate.identity;
							continue;
						}
						
						Write-Host "Importing $($iisCertificate.identity)";
						$certPath = $iisCertificate.path;
						
						Import-IIS7PfxCertificate -certPath "$certPath" -pfxPass $iisCertificate.password;
					}
				
					Write-Host "Done." -ForegroundColor Yellow;
				}

				# IIS Bindings
				if( $configuration.IIS.WebBindings -and $configuration.IIS.WebBindings.WebBinding )
				{
					Write-Host "Importing IIS bindings...";
							
					foreach( $iisWebBinding in $configuration.IIS.WebBindings.WebBinding )
					{
						Import-Module -Name WebAdministration;
																
						$existingBindingConfig = "$($iisWebBinding.ip):$($iisWebBinding.port):$($iisWebBinding.hostheader)";
						$existingBinding = Get-WebBinding | where {$_.bindingInformation -eq $existingBindingConfig -and $_.protocol -eq "$($iisWebBinding.protocol)"};							
								
						if($existingBinding -ne $null){
							Write-Host "Deleting already existing binding $($existingBindingConfig )";
							(Get-WebBinding | where {$_.bindingInformation -eq $existingBindingConfig -and $_.protocol -eq "$($iisWebBinding.protocol)"}) | Remove-WebBinding;
						}
						else{
							Write-Host "A binding with this config does not already exist: $($existingBindingConfig)";
						}
								
						Write-Host "Creating an IIS binding";
						New-WebBinding -Name $iisWebBinding.webApplicationIdentity -Port $iisWebBinding.port -HostHeader $iisWebBinding.hostheader -Protocol $iisWebBinding.protocol -IP $iisWebBinding.ip;

						Write-Host "Adding binding to hosts file";
						Windows-UpdateHostsFile 127.0.0.1 $($iisWebBinding.hostheader);
									
						if($iisWebBinding.protocol -eq "https")
						{
							Write-Host "Adding certificate to binding...";
							$commerceCert = ( Get-ChildItem -Path "cert:\localmachine\MY" | where { $_.FriendlyName -ieq $iisWebBinding.certificate -or $_.Subject -ieq "CN=$($iisWebBinding.certificate)" });
							$sslBinding = Get-WebBinding -Name $iisWebBinding.webApplicationIdentity -Port $iisWebBinding.port -HostHeader $iisWebBinding.hostheader -Protocol $iisWebBinding.protocol -IP $iisWebBinding.ip;
							$sslBinding.AddSslCertificate( $commerceCert.ThumbPrint, "MY" );
						}
					}

					Write-Host "Done." -ForegroundColor Yellow;
				}
				else
				{
					Write-Host "No SPWebApplication IIS web bindings defined in the Environment.xml file." -ForegroundColor Yellow;
				}

				if($configuration.IIS.WAMREG -and $configuration.IIS.WAMREG.UserAccounts -and $configuration.IIS.WAMREG.UserAccounts.UserAccount){
					$userAccounts = $configuration.IIS.WAMREG.UserAccounts.SelectNodes("UserAccount");
					
					Write-Host "Setting permissions on IIS WAMREG admin service..." -ForegroundColor Green;
					foreach( $userAccount in $userAccounts )
					{
						$user = $configuration.UserAccounts.UserAccount | where { $_.identity -ieq $($userAccount.userAccountIdentity) }

						Write-Host "DCOM rights for `"IIS WAMREG admin service`" needs to be adjusted to allow RuntimeUser to activate locally.";
						$returnValue = Start-Process -FilePath  (Join-Path -Path $DEPLOYMENT_DIRECTORY -ChildPath "\tools\dcomperm.exe") -ArgumentList @("-al '{61738644-F196-11D0-9953-00C04FD919C1}'", "set $($user.domain)\$($user.username) permit level:l") -NoNewWindow -Wait -PassThru;
						
						if( $returnValue.ExitCode -ne 0 )
						{
							Write-Error "Program Exit Code was $($returnValue.ExitCode), aborting.`r$($returnValue.StandardError)";
						}						
					}					
				}
			}

			if($configuration.CommerceServer){
				if($configuration.CommerceServer.Configure){
					$stagingUser = $configuration.UserAccounts.UserAccount | where { $_.identity -ieq $($configuration.CommerceServer.Configure.stagingUser) };
					$mailerUser = $configuration.UserAccounts.UserAccount | where { $_.identity -ieq $($configuration.CommerceServer.Configure.mailerUser) }
				
					CS2007-Configure $($CS_SQL_Server) $stagingUser.domain $stagingUser.username $stagingUser.password $mailerUser.domain $mailerUser.username $mailerUser.password
				}
			
				if($configuration.CommerceServer.Pup){
					$pupLocation = $configuration.CommerceServer.Pup.pupLocation;
					$iniLocation = $configuration.CommerceServer.Pup.iniLocation;
					Write-Host "Performing un-pup with $($pupLocation) and $($iniLocation)" -ForegroundColor Green;
					
					CS2007-UnpupWebServices $PROJECT_NAME $pupLocation $iniLocation;
				}
				
				if($configuration.CommerceServer.ProfileKeys -and $configuration.CommerceServer.ProfileKeys.create){
					if($configuration.CommerceServer.ProfileKeys.create -eq "true"){

						Write-Host "Creating profile keys...";
						Write-Host "Creating file..." -ForegroundColor Green;
						$returnValue = Start-Process -FilePath ( Join-Path $($Env:COMMERCE_SERVER_ROOT) -ChildPath "Tools\ProfileKeyManager.exe") -ArgumentList @( "/kn", "/o `"$($DEPLOYMENT_DIRECTORY)\ProfilesKeys.xml`"", "/f" ) -NoNewWindow -Wait -PassThru;
						
						if( $returnValue.ExitCode -ne 0 )
						{
							Write-Error "Program Exit Code was $($returnValue.ExitCode), aborting.`r$($returnValue.StandardError)";
						}						
						
						Write-Host "Setting 32bit registry..." -ForegroundColor Green;
						$returnValue = Start-Process -FilePath ( Join-Path $($Env:COMMERCE_SERVER_ROOT) -ChildPath "Tools\ProfileKeyManager.exe") -ArgumentList @( "/ke", "/kf `"$($DEPLOYMENT_DIRECTORY)\ProfilesKeys.xml`"", "/reg HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\CommerceServer\9.0\Keys\$($PROJECT_NAME)", "/f" ) -NoNewWindow -Wait -PassThru;
						
						if( $returnValue.ExitCode -ne 0 )
						{
							Write-Error "Program Exit Code was $($returnValue.ExitCode), aborting.`r$($returnValue.StandardError)";
						}						
						
						Write-Host "Setting 64bit registry..." -ForegroundColor Green;
						$returnValue = Start-Process -FilePath ( Join-Path $($Env:COMMERCE_SERVER_ROOT) -ChildPath "Tools\ProfileKeyManager.exe") -ArgumentList @( "/ke", "/kf `"$($DEPLOYMENT_DIRECTORY)\ProfilesKeys.xml`"", "/reg HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\CommerceServer\9.0\Keys\$($PROJECT_NAME)", "/f" ) -NoNewWindow -Wait -PassThru;
						
						if( $returnValue.ExitCode -ne 0 )
						{
							Write-Error "Program Exit Code was $($returnValue.ExitCode), aborting.`r$($returnValue.StandardError)";
						}					
					}
				}				
				
				if($configuration.CommerceServer.Azman){
					Write-Host "Updating AzMan Files" -ForegroundColor Green;
					
					$azManEntries = $configuration.CommerceServer.Azman.SelectNodes("Definition");
					
					foreach( $azman in $azManEntries )
					{
						if(Test-Path $($azman.FilePath))
						{
							Write-Host "Adding entry to $($azman.FilePath)" -ForegroundColor Green;
							
							Set-ItemProperty $($azman.FilePath) -name IsReadOnly -value $false;
							
							$azmanDomain = "";
							$azmanUser = "";
							
							if($($azman.userAccountIdentity) -eq $null -or $($azman.userAccountIdentity) -eq ""){
								$azmanDomain = $azman.UserOrGroupDomain;
								$azmanUser = $azman.UserOrGroupName;							
							}
							else{
								$azmanUser = $configuration.UserAccounts.UserAccount | where { $_.identity -ieq $($azman.userAccountIdentity) }
								
								$azmanDomain = $azmanUser.domain;
								$azmanUser = $azmanUser.username;										
							}
							
							if($($azman.ScopeName) -eq $null -or $($azman.ScopeName) -eq ""){
								Add-AZAddToRole $($azman.FilePath) $($azman.ApplicationName) $($azman.RoleName) $($azmanDomain) $($azmanUser);
							}
							else{
								Add-AZAddToRoleInScope $($azman.FilePath) $($azman.ApplicationName) $($azman.ScopeName) $($azman.RoleName) $($azmanDomain) $($azmanUser);
							}
						}
						else{
							Write-Host "$($azman.FilePath) does not exist, skipping." -ForegroundColor Red;
						}
					}
				}
			
				if($configuration.CommerceServer.Databases -or $configuration.CommerceServer.WebServices -or $configuration.CommerceServer.Schemas -or$configuration.CommerceServer.DatabaseScripts.DatabaseScript){
					$csServiceWebsite = $configuration.IIS.Websites.Website | where { $_.identity -ieq "CSServices" };
					$bizDeskHost = "$($csServiceWebsite.serverName)";
					
					if( ( $csServiceWebsite.port ) -and ( $csServiceWebsite.port -ne "" ) )
					{
						$bizDeskHost = "$($bizDeskHost):$($csServiceWebsite.port)";
					}			
				
					if(($CS_DB_Folder -ne $null) -and ($CS_DB_Folder -ne ""))
					{
						if(!(Test-Path "$($CS_DB_Folder)"))
						{
							Write-Host "Creating folder for CS databases: $($CS_DB_Folder)" -ForegroundColor Green;
							New-Item -Path "$($CS_DB_Folder)" -type directory | Out-Null;
						}
						else
						{
							Write-Host "CS databases folder already exists." -ForegroundColor Green;;
						}
					}
					
					$SQL_VARIABLES_BASE=@(
						"CS_USER_RUNTIME=`"$(( $configuration.UserAccounts.UserAccount | where { $_.identity -ieq "CSRuntimeUser" }).domain )\$(( $configuration.UserAccounts.UserAccount | where { $_.identity -ieq "CSRuntimeUser" }).userName )`"",
						"CS_USER_FOUNDATION=`"$(( $configuration.UserAccounts.UserAccount | where { $_.identity -ieq "CSFoundationUser" }).domain )\$(( $configuration.UserAccounts.UserAccount | where { $_.identity -ieq "CSFoundationUser" }).userName )`"",
						"CS_USER_SPFARMADMIN=`"$(( $configuration.UserAccounts.UserAccount | where { $_.identity -ieq "SPFarmAdminUser" }).domain )\$(( $configuration.UserAccounts.UserAccount | where { $_.identity -ieq "SPFarmAdminUser" }).userName )`"",
						"CS_USER_CATALOG=`"$(( $configuration.UserAccounts.UserAccount | where { $_.identity -ieq "CSCatalogUser" }).domain )\$(( $configuration.UserAccounts.UserAccount | where { $_.identity -ieq "CSCatalogUser" }).userName )`"",
						"CS_USER_CATALOG_PASSWORD=`"$(( $configuration.UserAccounts.UserAccount | where { $_.identity -ieq "CSCatalogUser" }).password )`"",
						"CS_USER_MARKETING=`"$(( $configuration.UserAccounts.UserAccount | where { $_.identity -ieq "CSMarketingUser" }).domain )\$(( $configuration.UserAccounts.UserAccount | where { $_.identity -ieq "CSMarketingUser" }).userName )`"",
						"CS_USER_ORDERS=`"$(( $configuration.UserAccounts.UserAccount | where { $_.identity -ieq "CSOrdersUser" }).domain )\$(( $configuration.UserAccounts.UserAccount | where { $_.identity -ieq "CSOrdersUser" }).userName )`"",
						"CS_USER_PROFILES=`"$(( $configuration.UserAccounts.UserAccount | where { $_.identity -ieq "CSProfilesUser" }).domain )\$(( $configuration.UserAccounts.UserAccount | where { $_.identity -ieq "CSProfilesUser" }).userName )`"",
						"CS_USER_BIZTALK=`"$(( $configuration.UserAccounts.UserAccount | where { $_.identity -ieq "CSBizTalkUser" }).domain )\$(( $configuration.UserAccounts.UserAccount | where { $_.identity -ieq "CSBizTalkUser" }).userName )`"",
						"CS_USER_FARMADMIN=`"$(( $configuration.UserAccounts.UserAccount | where { $_.identity -ieq "SPFarmAdminUser" }).domain )\$(( $configuration.UserAccounts.UserAccount | where { $_.identity -ieq "SPFarmAdminUser" }).userName )`"",
						"CS_DB_NAME_CATALOG=`"$(( $configuration.CommerceServer.Databases.Database | where { $_.identity -ieq "CSCatalog" }).databaseName )`"",
						"CS_DB_NAME_MARKETING_LISTS=`"$(( $configuration.CommerceServer.Databases.Database | where { $_.identity -ieq "CSMarketingLists" }).databaseName )`"",
						"CS_DB_NAME_MARKETING=`"$(( $configuration.CommerceServer.Databases.Database | where { $_.identity -ieq "CSMarketing" }).databaseName )`"",
						"CS_DB_NAME_PROFILES=`"$(( $configuration.CommerceServer.Databases.Database | where { $_.identity -ieq "CSProfiles" }).databaseName )`"",
						"CS_DB_NAME_ORDERS=`"$(( $configuration.CommerceServer.Databases.Database | where { $_.identity -ieq "CSOrders" }).databaseName )`"",
						"CS_DB_NAME_ORDERS_CONFIG=`"$(( $configuration.CommerceServer.Databases.Database | where { $_.identity -ieq "CSOrdersConfig" }).databaseName )`"",
						"CS_DB_NAME_ADMIN=`"$(( $configuration.CommerceServer.Databases.Database | where { $_.identity -ieq "CSAdmin" }).databaseName )`"",
						"CS_DB_NAME_CATALOG_SCRATCH=`"$(( $configuration.CommerceServer.Databases.Database | where { $_.identity -ieq "CSCatalogScratch" }).databaseName )`"",
						"CS_DB_Folder=`"$($CS_DB_Folder)`"",
						"SOLUTION_BASE_DIRECTORY=`"$($SOLUTION_BASE_DIRECTORY)`"",
						"PROJECT_NAME=`"$($PROJECT_NAME)`""
						"CS_BIZDESKHOST=`"$($bizDeskHost)`""
					);										
					
					if($configuration.CommerceServer.WebServices){
						Write-Host "Updating Web Services" -ForegroundColor Green;
						
						$directories = ( Get-ChildItem -Path ( Join-Path -Path $SOLUTION_BASE_DIRECTORY -ChildPath "WebServices" ) ) | Where {$_.psIsContainer -eq $true};
						foreach( $webService in $configuration.CommerceServer.WebServices.WebService )
						{
							$webSiteTargetDir = "";
							
							if($webService.targetPath){
								$webSiteTargetDir = $webService.targetPath;
							}
							else{
								$webSiteTargetDir = $webService.path;
							}
							
							Write-Host "Setting path for $($webService.virtualDirectoryPath) to be $webSiteTargetDir...";
							# get the website object from IIS and assign it's physical path
							$website = $configuration.IIS.Websites.Website | where { $_.identity -ieq $webService.websiteIdentity };
							Set-ItemProperty -Path "IIS:\\Sites\$($website.identity)\$($webService.virtualDirectoryPath)" -Name "physicalPath" -Value $webSiteTargetDir;
							
							# if the targetPath property is specified then the path should be copied to the targetPath
							if($webService.targetPath){
								Write-Host "Copying files from $($webService.path) to $webSiteTargetDir...";
								
								if(Test-Path "$webSiteTargetDir" -PathType Any){
									Write-Host "Deleting existing folder...";
									Remove-Item "$webSiteTargetDir" -Recurse -Force -Confirm:$false;
								}
								
								Copy-Item "$($webService.path)" "$webSiteTargetDir" -Recurse -Force -Confirm:$false;
							}
							
							# make sure that the web service has permissions to access the folder
							$iisWebApplication = Get-WebApplication -Site $website.identity -Name $webService.virtualDirectoryPath;
							$iisAppPoolName = $iisWebApplication.Attributes["applicationpool"].Value;
							$appPoolNode = Get-Item "IIS:\AppPools\$iisAppPoolName";
							$appPoolUserName = $appPoolNode.processModel.userName;
							
							Write-Host "Granting $appPoolUserName access to $($webSiteTargetDir)...";
							# we should look into making the permissions configurable
							Windows-GrantFullReadWriteAccessToFolder "$($webSiteTargetDir)" $appPoolUserName;
							
							#Write-Host "Removing read-only flag from AuthorizationStore.xml file...";
							# make sure the AuthorizationStore.xml file is not read only
							#$fullAuthPath = ( Join-Path -Path $webSiteTargetDir -ChildPath "*AuthorizationStore.xml");
							#$authFile = Get-Childitem "$fullAuthPath";
							#$authFile.IsReadonly = $false;
						}
						
						Add-StartUpRoles;
					}
					
					if($configuration.CommerceServer.Schemas){
						
						Write-Host "Updating Profile Schemas";
						if( $configuration.CommerceServer.Schemas.ProfilesSchema )
						{
							foreach( $profilesSchema in $configuration.CommerceServer.Schemas.ProfilesSchema )
							{
								Write-Host "$($profilesSchema.path)" -ForegroundColor Green;
								Import-CS2007ProfileSchema -CommerceSitename $configuration.CommerceServer.identity -FilePath $profilesSchema.path;
							}
						}

						Write-Host "Updating Catalog Schemas";
						if( $configuration.CommerceServer.Schemas.CatalogSchema )
						{
							foreach( $catalogSchema in $configuration.CommerceServer.Schemas.CatalogSchema )
							{
								Write-Host "$($catalogSchema.path)" -ForegroundColor Green;
								Import-CS2007CatalogSchema -CommerceSitename $configuration.CommerceServer.identity -FilePath $catalogSchema.path -Replace ( $catalogSchema.replace -ieq "true" ) -Transacted ( $catalogSchema.transacted -ieq "true" ) -AllowSchemaUpdate ( $catalogSchema.allowSchemaUpate -ieq "true" );
								
								if($catalogSchema.AzMan -and $catalogSchema.AzMan.File){
									
									Write-Host "Updating AzMan files associated to catalog..." -ForegroundColor Green;
									
									foreach($file in $catalogSchema.AzMan.File){
										Update-CatalogAuthStore $file.siteName $file.name;
									}
								}
							}
						}

						Write-Host "Upating Catalog Inventory Schemas";
						if( $configuration.CommerceServer.Schemas.CatalogInventorySchema )
						{
							foreach( $catalogInventorySchema in $configuration.CommerceServer.Schemas.CatalogInventorySchema )
							{
								Write-Host "$($catalogInventorySchema.path)" -ForegroundColor Green;
								Import-CS2007InventorySchema -CommerceSitename $configuration.CommerceServer.identity -FilePath $catalogInventorySchema.path;
							}
						}

#						Write-Host "Importing Marketing sample data";
#						$returnValue = Start-Process -FilePath ( Join-Path -Path $DEPLOYMENT_DIRECTORY -ChildPath "MarketingUtilities.exe" ) -Wait -NoNewWindow -WorkingDirectory $DEPLOYMENT_DIRECTORY -ArgumentList "/importmarketingschema" -PassThru;
#						Write-Host $returnValue.StandardOutput;
#						if( $returnValue.ExitCode -ne 0 )
#						{
#							Write-Error -Message $returnValue.StandardError -ErrorId $returnValue.ExitCode ;
#						}
					}

					if($configuration.CommerceServer.DatabaseScripts.DatabaseScript ){
						Write-Host "Updating CS databases...";
			
						Add-SQLPSSnapin;
						
						foreach( $databaseScript in $configuration.CommerceServer.DatabaseScripts.DatabaseScript )
						{
							Write-Host "$($databaseScript.path)" -ForegroundColor Green;
							$databaseIdentity = ( $configuration.CommerceServer.Databases.Database | where { $_.identity -ieq $databaseScript.databaseIdentity } ) ;

							$SQL_VARIABLES = $SQL_VARIABLES_BASE;
							$SQL_VARIABLES += "CS_DB_SERVER=`"$($databaseIdentity.serverName)`"";
							$SQL_VARIABLES += "PROJECT_NAME_VARIATIONS=`"Canada`"";
							
							$SQL_VARIABLES_STRING = [System.String]::Join( " -v ", $SQL_VARIABLES );
							$returnValue = Start-Process -Wait -NoNewWindow -PassThru -WorkingDirectory $DEPLOYMENT_DIRECTORY -FilePath $SQLCMD_PATH -ArgumentList @( "-b", "-E", "-S $($databaseIdentity.serverName)", "-i `"$($databaseScript.path)`"", "-v $($SQL_VARIABLES_STRING)");
							Write-Host $returnValue.StandardOutput;
							if( $returnValue.ExitCode -ne 0 )
							{
								if( $Error )
								{
									Write-Host $Error -ForegroundColor Red;
								}
								Write-Error -Message $returnValue.StandardError -ErrorId $returnValue.ExitCode ;
							}
						}
					}	
				
					Write-Host "Setting the Commerce Server Display Out-of-Stock items flag" -ForegroundColor Green;
					Set-CSConfigInventoryPropertyFlag -CommerceSiteName $configuration.CommerceServer.identity -CommercePropertyName "f_display_oos_skus" -CommercePropertyValue $true;				
				}
			
			}		
					
			# File tokens
			if( $configuration.FileTokens -and $configuration.FileTokens.FileToken ){
				
				$files = $configuration.SelectNodes("FileTokens/FileToken");
				
				$TOKENS=@(
						"#CatalogDBName=$(( $configuration.CommerceServer.Databases.Database | where { $_.identity -ieq "CSCatalog" }).databaseName )",
						"#PrivateSiteDomain=$(( $configuration.Variables.Variable | where { $_.identity -ieq "PrivateUrlDomain" }).value )",
						"#ExtendedDBName=$(( $configuration.CommerceServer.Databases.Database | where { $_.identity -ieq "CSExtended" }).databaseName )",
						"#ProjectName=$($PROJECT_NAME)",
						"#DomainName=$($DOMAIN_NAME)",
						"#RuntimeUser=$(( $configuration.UserAccounts.UserAccount | where { $_.identity -ieq "CSRuntimeUser" }).username )"
						 );
				
				Write-Host "Replacing file tokens";				
				foreach( $file in $files)
				{
					Write-Host "Removing read-only flag for $($file.filePath)" ;
					# make sure the  file is not read only
					Set-ItemProperty ($file.filePath) -name IsReadOnly -value $false
											
					Write-Host "$($file.filePath)" -ForegroundColor Green;
					foreach ( $token in $TOKENS ) 
					{		
						$content = Get-Content -path $file.filePath;
						$keyValue = $token -split "=";			
						$content -replace $keyValue[0], $keyValue[1] | Set-Content $file.filePath;
					}
				}
			}

			#create any required folders and assign permissions
			if($configuration.Folders -and $configuration.Folders.Folder){
				Write-Host "Creating folders..." -ForegroundColor Green;
				
				$folders = $configuration.SelectNodes("Folders/Folder");
			
				foreach($folder in $folders){
					if ((Test-Path $folder.path) -ne $true){
						Write-Host "Creating $($folder.path)";
						
						New-Item $folder.path -type directory > $null;											
					}
					else{
						Write-Host "$($folder.path) already exists will not re-create.";
					}
					
					if($folder.UserAccounts -and $folder.UserAccounts.UserAccount){
						Write-Host "Creating permissions for $($folder.path)";
						
						$users = $folder.SelectNodes("UserAccounts/UserAccount");
					
						foreach($user in $users){
							$userAccount = $configuration.UserAccounts.UserAccount | where { $_.identity -ieq $user.userAccountIdentity};
							
							Write-Host "Creating permissions for $($userAccount.domain)\$($userAccount.username) on $($folder.path)";
							Windows-GrantFullReadWriteAccessToFolder "$($folder.path)" "$($userAccount.domain)\$($userAccount.username)";
						}
					}					
				}
			}

			Write-Host "Done." -ForegroundColor Yellow;
		}
		
		if( $configuration.CommerceServer -and $configuration.CommerceServer.Pipelines)
		{
			Write-Host "Registering pipelines";
			
			$pipelines = $configuration.CommerceServer.SelectNodes("Pipelines/Pipeline");
			
			foreach( $pipeline in $pipelines )
			{
				$dllPath = "$($pipeline.dllPath)"
				$tlbPath32 = "$($pipeline.dllPath).32.tlb"
				$tlbPath64 = "$($pipeline.dllPath).64.tlb"
				$argumentList64 = @( "`"$dllPath`"", "/codebase", "/tlb:`"$tlbPath64`"" );
				$argumentList32 = @( "`"$dllPath`"", "/codebase", "/tlb:`"$tlbPath32`"" );
				$argumentListReg = @( "/s", $pipeline.regPath );

				if (Test-Path $dllPath)
				{
					Write-Host "Registering $($pipeline.identity)";
					Write-Host "64 bit" -ForegroundColor Green;
					$returnValue = Start-Process -FilePath $REGASM_64_PATH -Wait -NoNewWindow -ArgumentList $argumentList64 -PassThru;
					Write-Host $returnValue.StandardOutput;
					if( $returnValue.ExitCode -ne 0 )
					{
						Write-Error -Message $returnValue.StandardError -ErrorId $returnValue.ExitCode ;
					}

					Write-Host "32 bit" -ForegroundColor Green;
					$returnValue = Start-Process -FilePath $REGASM_PATH -Wait -NoNewWindow -ArgumentList $argumentList32 -PassThru;
					Write-Host $returnValue.StandardOutput;
					if( $returnValue.ExitCode -ne 0 )
					{
						Write-Error -Message $returnValue.StandardError -ErrorId $returnValue.ExitCode ;
					}

					Write-Host "Adding registry entries";
					Write-Host "64 bit" -ForegroundColor Green;
					$returnValue = Start-Process -FilePath $REGEDIT_64_PATH -Wait -NoNewWindow -ArgumentList $argumentListReg -PassThru;
					Write-Host $returnValue.StandardOutput;
					if( $returnValue.ExitCode -ne 0 )
					{
						Write-Error -Message $returnValue.StandardError -ErrorId $returnValue.ExitCode ;
					}

					Write-Host "32 bit" -ForegroundColor Green;
					$returnValue = Start-Process -FilePath $REGEDIT_PATH -Wait -NoNewWindow -ArgumentList  $argumentListReg -PassThru;
					Write-Host $returnValue.StandardOutput;
					if( $returnValue.ExitCode -ne 0 )
					{
						Write-Error -Message $returnValue.StandardError -ErrorId $returnValue.ExitCode ;
					}
				}
				else
				{
					Write-Host -Message "Could not register pipeline components in '$dllPath' - file not found." -ForegroundColor Yellow;
				}
			}
		}		

		if($configuration.Files -and $configuration.Files.File){
			
			$files = $configuration.Files.SelectNodes("File");
		
			foreach($file in $files){
				if($file.UserAccounts -and $file.UserAccounts.UserAccount){
					Write-Host "Creating permissions for $($file.path)";
					
					$users = $file.SelectNodes("UserAccounts/UserAccount");
				
					foreach($user in $users){
						$userAccount = $configuration.UserAccounts.UserAccount | where { $_.identity -ieq $user.userAccountIdentity};
						
						Write-Host "Creating permissions for $($userAccount.domain)\$($userAccount.username) on $($file.path)";
						Windows-GrantFullReadWriteAccessToFile "$($file.path)" "$($userAccount.domain)\$($userAccount.username)";
					}
				}				
			}
		}
		
		if($configuration.Registry -and $configuration.Registry.File){
		
			Write-Host "Running registry files..." -ForegroundColor Green;
			
			$files = $configuration.Registry.SelectNodes("File");
			
			foreach( $file in $files )
			{
				$argumentListReg = @( "/s", $file.path );
			
				Write-Host "Running file $($file.path)";
				Write-Host "64 bit" -ForegroundColor Green;
				$returnValue = Start-Process -FilePath $REGEDIT_64_PATH -Wait -NoNewWindow -ArgumentList $argumentListReg -PassThru;
				Write-Host $returnValue.StandardOutput;
				if( $returnValue.ExitCode -ne 0 )
				{
					Write-Error -Message $returnValue.StandardError -ErrorId $returnValue.ExitCode ;
				}

				Write-Host "32 bit" -ForegroundColor Green;
				$returnValue = Start-Process -FilePath $REGEDIT_PATH -Wait -NoNewWindow -ArgumentList  $argumentListReg -PassThru;
				Write-Host $returnValue.StandardOutput;
				if( $returnValue.ExitCode -ne 0 )
				{
					Write-Error -Message $returnValue.StandardError -ErrorId $returnValue.ExitCode ;
				}
			}
		}		

		if( $Postcompile ){
			Write-Host "Running post-compile." -ForegroundColor Green;
			
			# File tokens
			if( $configuration.FileTokens -and $configuration.FileTokens.FileToken ){
				
				$files = $configuration.SelectNodes("FileTokens/FileToken");
				
				$TOKENS=@(
						"#CatalogDBName=$(( $configuration.CommerceServer.Databases.Database | where { $_.identity -ieq "CSCatalog" }).databaseName )",
						"#PrivateSiteDomain=$(( $configuration.Variables.Variable | where { $_.identity -ieq "PrivateUrlDomain" }).value )",
						"#ExtendedDBName=$(( $configuration.CommerceServer.Databases.Database | where { $_.identity -ieq "CSExtended" }).databaseName )",
						"#ProjectName=$($PROJECT_NAME)",
						"#DomainName=$($DOMAIN_NAME)",
						"#RuntimeUser=$(( $configuration.UserAccounts.UserAccount | where { $_.identity -ieq "CSRuntimeUser" }).username )"
						 );
				
				Write-Host "Replacing file tokens";				
				foreach( $file in $files)
				{
					Write-Host "Removing read-only flag for $($file.filePath)" ;
					# make sure the  file is not read only
					Set-ItemProperty ($file.filePath) -name IsReadOnly -value $false
											
					Write-Host "$($file.filePath)" -ForegroundColor Green;
					foreach ( $token in $TOKENS ) 
					{		
						$content = Get-Content -path $file.filePath;
						$keyValue = $token -split "=";			
						$content -replace $keyValue[0], $keyValue[1] | Set-Content $file.filePath;
					}
				}
			}
		}
		
		$success = "SUCCESSFUL";
	}
	catch
	{
		foreach( $errorRecord in $Error )
		{
			Write-Host -Object $errorRecord -ForegroundColor Red;
			Write-Host -Object $errorRecord.InvocationInfo.PositionMessage -ForegroundColor Red;
		}
	}
	finally
	{
		$scriptEndDate = Get-Date;
		$scriptDuration = New-TimeSpan -Start $scriptStartDate -End $scriptEndDate;
		Write-Host "Script ended @ $($scriptEndDate) ( $($scriptDuration.Minutes) minutes, $($scriptDuration.Seconds) seconds. ).";

		if( Get-WinEvent -MaxEvents 1 -FilterHashTable @{LogName="*"; StartTime=$scriptStartDate} -Oldest | where { $_.LevelDisplayName -ieq 'Error' -or $_.LevelDisplayName -eq 'Critical' } )
		{
			Get-WinEvent -FilterHashTable @{LogName="*"; StartTime=$scriptStartDate} -Oldest | where { $_.LevelDisplayName -ieq 'Error' -or $_.LevelDisplayName -eq 'Critical' } | Format-List;
		}
		
		if( Get-Job )
		{
			Stop-Job -Name *;
		}

		Stop-Transcript;
		
		# Deliver the results to the email address of the logged in user

		if( $SEND_EMAIL -ne "false" )
		{
			Write-Host "Sending email..." -ForegroundColor Green;
			$root =  New-Object System.DirectoryServices.DirectoryEntry;
			$objSearcher = New-Object System.DirectoryServices.DirectorySearcher $root, "(&(objectCategory=User)(sAMAccountName=$($Env:UserName)))", @( "mail" ), ( [System.DirectoryServices.SearchScope]::Subtree );
			$colResults = $objSearcher.FindOne();
			$emailAddress = $colResults.Properties["mail"];

			if( $emailAddress )
			{
				Send-MailMessage -To $emailAddress -From "no_reply@cactuscommerce.com" -Subject "Deploy on $($Env:COMPUTERNAME) $($success)." -Attachments @( $transactionLogPath ) -SmtpServer "mail.cactus.ca";
			}

			if ($Error.Count -gt 0)
			{
				Write-Host "Terminating execution of script(s) because an error(s) occured." -ForegroundColor Red;
				exit 1;
			}
		}
		else
		{
			Write-Host "Email will not be sent because SEND_EMAIL is false." -ForegroundColor Yellow;
		}
	}
}
